﻿



namespace SSS.AlphaNN.Forms
{
    using System;
    using System.Threading;
    using System.Windows.Forms;
    using SSS.AlphaNN.Logic;
    using Components;
    using System.Collections.Generic;
    using System.Linq;
    using System.Data;
    using System.Drawing;

    public partial class MainFormClassic
    {


        /// <summary>
        /// Ловим сообщения для того что бы отображать порты в рабочей области
        /// </summary>
        /// <param name="m"></param>
        /// <returns></returns>
        protected override bool ProcessKeyPreview(ref Message m)
        {
            //MessageBox.Show( m.Msg.ToString( "X" ) );
            switch (m.Msg)
            {
                case 0x0100: //WM_KEYDOWN
                    switch (m.WParam.ToInt32())
                    {
                        case 0x1B: //ESC
                            wrkGround.RemoveMarkFromAllObjs(true);
                            break;

                        case 0x10: //VK_SHIFT
                            wrkGround.IsShiftPressed = true;
                            //this.Text = wrkGround.IsShiftPressed.ToString();  //for testing purpose
                            break;

                        case 0x2E: //VK_DELETE
                            wrkGround.EraseMarkedObjs();
                            break;

                        case 0x5A: //VK_Z
                            wrkGround.ShowAnimate();
                            //wrkGround.Scale(-1);
                            break;

                        case 0x58: //VK_X
                            //wrkGround.Scale( 1 );

                            break;



                    }

                    break;

                case 0x0101: //WM_KEYUP

                    switch (m.WParam.ToInt32())
                    {
                        case 0x10: //VK_SHIFT
                            wrkGround.IsShiftPressed = false;
                            // this.Text = wrkGround.IsShiftPressed.ToString();
                            break;

                        //case 0x70: //VK_F1

                        //wrkGround.DumpGhost();

                        //break;

                        //case 0x71: //VK_F2
                        //wrkGround.LoadGhostDump();

                        //break;
                    }

                    break;
            }

            return base.ProcessKeyPreview(ref m);

        }


        /// <summary>
        /// Закрытие формы
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void CloseForm(object sender, EventArgs e)
        {
            this.Close();
        }


        /// <summary>
        /// Убирает всё то, что натворил пользователь, понимаешь, в рабочей области
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ClearWorkGroundFixed(object sender, EventArgs e)
        {
            int i = tabControl1.SelectedIndex;
            WorkGround wkgr = new WorkGround();
            tool = Tools.Pointer;

            ToolSwitch();
            wkgr.FileName = liWorkGround[i].FileName;
            tabControl1.TabPages[i].Controls.Remove(liWorkGround[i]);
            liWorkGround.RemoveAt(i);
            wkgr.Dock = DockStyle.Fill;
            liWorkGround.Insert(i, wkgr);
            tabControl1.TabPages[i].Controls.Add(wkgr);

        }


        /// <summary>
        /// Завершение всех нитей
        /// </summary>
        protected void AbortAllThread()
        {

            if (threadForLearnNeuronNetwork != null && threadForLearnNeuronNetwork.ThreadState == ThreadState.Running)
            {
                threadForLearnNeuronNetwork.Abort();
            }
            if (threadForRunNeuronNetwork != null && threadForRunNeuronNetwork.ThreadState == ThreadState.Running)
            {
                threadForRunNeuronNetwork.Abort();
            }
        }


        /// <summary>
        /// Метод для анимации нейронной сети
        /// </summary>
        private void AnimationNeuronNetwork()
        {
            try
            {
                if (groupNeuronAnim != null)
                {
                    bool run = threadForRunNeuronNetwork != null && threadForRunNeuronNetwork.IsAlive;
                    bool learn = threadForLearnNeuronNetwork != null && threadForLearnNeuronNetwork.IsAlive;
                    while (run || learn)
                    {
                        for (int i = 0; i < groupNeuronAnim.Count; i++)
                        {
                            Parallel.For(0, groupNeuronAnim[i].Count, (x) =>
                            {
                                groupNeuronAnim[i][x].DoAnimate();
                                Thread.Sleep(100);
                                groupNeuronAnim[i][x].DoAnimate();
                            });
                            Thread.Sleep(100);
                        }
                        run = threadForRunNeuronNetwork != null && threadForRunNeuronNetwork.IsAlive;
                        learn = threadForLearnNeuronNetwork != null && threadForLearnNeuronNetwork.IsAlive;
                    }
                }
            }
            catch (Exception)
            {
                ;
            }
            
        }

        /// <summary>
        /// "Концовка" для анимации
        /// </summary>
        private void EndForAnimation()
        {
            if (animation != null)
                switch (animation.ThreadState)
                {
                    case ThreadState.Running:
                    case ThreadState.Stopped:
                    case ThreadState.Background:
                        animation.Abort();
                        break;
                }
        }


        /// <summary>
        /// Запуск нейронной сети
        /// </summary>
        protected void RunNeuronNetwork(object i)
        {
            try
            {
                if (liWorkGround[(int)i].IsRun)
                {
                    WorkingNetworkNeuronDouble ww = new WorkingNetworkNeuronDouble(liWorkGround[(int)i]);
                    groupNeuronAnim = ww.TopologySort();
                    animation = new Thread(new ThreadStart(AnimationNeuronNetwork));
                    animation.Start();
                    List<List<double>> liOutput = ww.RunNeuronNetwork(groupNeuronAnim);

                    if (liOutput.Count > 0)
                    {
                        ChangeEnabledRibbonButton c = delegate()
                                                          {

                                                              ViewDBTable vdb = new ViewDBTable(liOutput);
                                                              vdb.ShowDialog();
                                                          };
                        this.Invoke(c);
                    }
                    EndForAnimation();
                }
                else
                {
                    MessageBox.Show("Неверно сделана архитектура нейронной сети!", "Ошибка!", MessageBoxButtons.OK,
                              MessageBoxIcon.Error);

                }
                // 
                //их сортировка
                //собственно запуск нейронной сети
                //Получение результата
            }
            catch (ThreadAbortException)
            {
                if (animation != null)
                    animation.Abort();
                Thread.ResetAbort();
            }
            catch(FormatException)
            {
                MessageBox.Show("Ошибка в архитектуре! Не поддерживаем реккурентные сети", "Ошибка",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                EndForAnimation();
                ChangeEnabledRibbonButton c = ForEndLearningAndRunningNetwork;

                this.Invoke(c);
            }
        }

        /// <summary>
        /// Обучение нейронной сети
        /// </summary>
        protected void LearnNeuronNetwork(object i)
        {
            try
            {
                if (liWorkGround[(int)i].IsRun && liWorkGround[(int)i].IsTeach)
                {
                    //считывание данных с визуального отображения
                    //их сортировка
                    //собственно обучение
                    //вывод на форму новой сети....
                    //И да поможет тому, кто будет делать обратную конвертацию из NeuronNetwork in WorkGround,
                    //разум... да не иссекнет его терпение! И да будет с ним сила, надежда!! 
                    //Да что-то я заговорился
                    //Пока даже не знаю.. Ну ладно сеть будет сразу отсортированной выводиться, веса поменяются.
                    //Придёться много таблиц Хэш применять.
                    //не придёться.

                    WorkingNetworkNeuronDouble ww = new WorkingNetworkNeuronDouble(liWorkGround[(int)i]);
                    var a = ww.TopologySort();
                    groupNeuronAnim = a;
                    animation = new Thread(new ThreadStart(AnimationNeuronNetwork));
                    animation.Start();
                    ww.LearningNetwork(a);
                }
                else
                {
                    MessageBox.Show("Неверно сделана архитектура нейронной сети!", "Ошибка!", MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                }


            }
            catch (ThreadAbortException)
            {
                if (animation != null)
                    animation.Abort();
                Thread.ResetAbort();
            }
            catch (FormatException)
            {
                MessageBox.Show("Ошибка в архитектуре! Не поддерживаем реккурентные сети", "Ошибка",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (DataException d)
            {
                MessageBox.Show(d.Message, "Error!!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                EndForAnimation();
                ChangeEnabledRibbonButton c = ForEndLearningAndRunningNetwork;
                this.Invoke(c);
            }
        }

        /// <summary>
        /// Создание страницы новой с нейронной сетью
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void CreateTabPage(object sender, EventArgs e)
        {
            WorkGround wkgr = new WorkGround();
            wkgr.Dock = DockStyle.Fill;

            TabPage NeuronNetworkPage2 = new TabPage();
            NeuronNetworkPage2.BackColor = SystemColors.GradientActiveCaption;
            NeuronNetworkPage2.Location = new System.Drawing.Point(4, 22);
            NeuronNetworkPage2.Name = "NeuronNetworkPage";
            NeuronNetworkPage2.Padding = new System.Windows.Forms.Padding(3);
            NeuronNetworkPage2.Size = new System.Drawing.Size(928, 479);
            NeuronNetworkPage2.TabIndex = 0;
            NeuronNetworkPage2.Text = "Нейронная сеть " + _countNeuronPage;
            _countNeuronPage++;
            NeuronNetworkPage2.UseVisualStyleBackColor = true;
            tabControl1.Controls.Add(NeuronNetworkPage2);
            int i = tabControl1.Controls.Count - 1;
            tabControl1.Controls[i].Select();
            tabControl1.SelectedIndex = i;
            tabControl1.SelectedTab.Controls.Add(wkgr);
            tabControl1.SelectedTab.BackColor = SystemColors.GradientActiveCaption;
            liWorkGround.Add(wkgr);

            ToolSwitch();
        }

        /// <summary>
        /// Переключатель инструментов
        /// </summary>
        protected void ToolSwitch()
        {
            int i = tabControl1.SelectedIndex;
            liWorkGround[i].RemoveMarkFromAllObjs(true);
            liWorkGround.ForEach(x => x.EndInsertion());


            foreach (object button in toolStrip1.Items)
            {
                if (button is ToolStripButton)
                    (button as ToolStripButton).Checked = false;
            }

            switch (tool)
            {
                case Tools.Neuron:
                    toolStripButtonNeuron.Checked = true;
                    liWorkGround.ForEach(x => x.BeginInsertion(typeof(Neuron)));
                    break;

                case Tools.Contact:
                    toolStripButtonContact.Checked = true;
                    break;

                case Tools.Teacher:
                    toolStripButtonTeacher.Checked = true;
                    liWorkGround.ForEach(x => x.BeginInsertion(typeof(Teacher)));
                    break;

                case Tools.DB:
                    toolStripButtonDB.Checked = true;
                    liWorkGround.ForEach(x => x.BeginInsertion(typeof(Source)));
                   

                    break;
                case Tools.FO:
                    toolStripButtonFO.Checked = true;
                    liWorkGround.ForEach(x => x.BeginInsertion(typeof(Sink)));
                    break;
                default:
                    toolStripButtonPointer.Checked = true;
                    break;
            }
        }


        protected void ShowAboutForm()
        {
            SSS.AlphaNN.Forms.AboutForm aboutForm = new SSS.AlphaNN.Forms.AboutForm();
            aboutForm.ShowDialog();
        }

        /// <summary>
        /// начальный этап подготовки к вычислениям или обучению
        /// </summary>
        protected void ForStartLearningAndRunningNeuronNetwork()
        {
            foreach (object button in toolStrip1.Items)
            {
                if (button is ToolStripButton)
                    (button as ToolStripButton).Enabled = false;
            }
            tool = Tools.Pointer;
            ToolSwitch();

            toolStripButtonPauseNetwork.Enabled = true;
            toolStripButtonStopNetwork.Enabled = true;

            wrkGround.Enabled = false;
        }


        /// <summary>
        /// конечный этап вычислений или обучения
        /// </summary>
        protected void ForEndLearningAndRunningNetwork()
        {

            foreach (object button in toolStrip1.Items)
            {
                if (button is ToolStripButton)
                    (button as ToolStripButton).Enabled = true;
            }

            toolStripButtonPauseNetwork.Enabled = false;
            toolStripButtonStopNetwork.Enabled = false;
            wrkGround.Enabled = true;
        }

        /// <summary>
        /// метод запускающий нейронную сеть
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void RunMethod(object sender, EventArgs e)
        {

            if (threadForRunNeuronNetwork == null || (threadForRunNeuronNetwork.ThreadState == ThreadState.Stopped))
            {
                ForStartLearningAndRunningNeuronNetwork();
                threadForRunNeuronNetwork = new Thread(new ParameterizedThreadStart(RunNeuronNetwork));
                threadForRunNeuronNetwork.Start(tabControl1.SelectedIndex);
            }
        }

        /// <summary>
        /// Метод для обучения нейронной сети
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void LearningMethod(object sender, EventArgs e)
        {
            if (threadForLearnNeuronNetwork == null || (threadForLearnNeuronNetwork.ThreadState == ThreadState.Stopped))
            {
                ForStartLearningAndRunningNeuronNetwork();
                threadForLearnNeuronNetwork = new Thread(new ParameterizedThreadStart(LearnNeuronNetwork));
                threadForLearnNeuronNetwork.Start(tabControl1.SelectedIndex);
            }
        }

        /// <summary>
        /// Метод для "сохранения как" нейронной сети 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void SaveAsNeuronNetwork(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "Бинарные мозги нейросети (*.bin)|*.bin";
            if (sfd.ShowDialog() == DialogResult.OK)
            {
                SaveNeuronNetwork(sfd.FileName);
            }
        }

        /// <summary>
        /// Просто сохранить
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void SaveNeuronNetwork(object sender, EventArgs e)
        {
            int count = tabControl1.SelectedIndex;
            if (liWorkGround[count].FileName != String.Empty)
            {
                SaveNeuronNetwork(liWorkGround[count].FileName);
            }
            else
            {
                SaveAsNeuronNetwork(sender, e);
            }
        }

        protected void SaveNeuronNetwork(string name)
        {
            int count = tabControl1.SelectedIndex;
            liWorkGround[count].FileName = name;
            liWorkGround[count].DumpGhost(name);
        }

        /// <summary>
        /// Сохранение файла
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OpenNeuronNetwork(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "*.xml | *.xml";

            if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {

                int count = tabControl1.SelectedIndex;
                // liWorkGround[count].FromXmlDocument(ofd.FileName);
                liWorkGround[count].ReDraw();
            }
        }

        /// <summary>
        /// Изменение масштаба
        /// </summary>
        /// <param name="percent">На сколько=)</param>
        protected void ScaleWorkGround(int percent)
        {
            int count = tabControl1.SelectedIndex;
            liWorkGround[count].Zoom = percent;
            liWorkGround[count].Scale(1);
        }

        /// <summary>
        /// Закрытие страницы
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClosePage(object sender, EventArgs e)
        {
            if (tabControl1.TabPages.Count > 1)
            {
                int count = tabControl1.SelectedIndex;
                tabControl1.TabPages.RemoveAt(count);
            }
            else
            {
                Close();
            }
        }
    }
}
